跳到主要内容

5.2-Service Worker

Create by fall on 22 Nov 2020
Recently revised in 28 Jul 2025

Service Worker

Service Worker 旨在创建有效的离线体验。可以使你的应用先访问本地缓存资源,所以在离线状态时,在没有通过网络接收到更多的数据前,仍可以提供基本的功能

Service Worker 可以拦截当前网站所有的请求,进行判断(需要编写相应的判断程序),如果需要向服务器发

service Worker 脱离于主线程之外的线程,用于解决性能问题,一些消耗时间,并且复杂的计算通过 service Worker 进行计算。

service worker 的特点

  • 独立的线程,有自己的 worker content,不能和主线程直接通信,必须通过消息完成。
  • 不能使用诸如 alert()confirm() 方法
  • 一旦被 install 就会一直存在,除非被 uninstall
  • 不需要时,会进行休眠
  • 可以拦截代理请求和返回,缓存的文件可以被读取到
  • 离线的内容,开发者可控
  • 可以向客户端推送信息
  • 分配给 Worker 线程运行的脚本文件,必须与主线程的脚本文件同源。
  • 不能直接操作 DOM
  • 不能操作本地磁盘中的数据
  • 必须是 https 协议,或者是 localhost 环境下才能工作

分配给 Worker 线程运行的脚本文件,必须与主线程的脚本文件同源。

使用步骤

  • service worker URL 通过 serviceWorkerContainer.register() 用于获取和注册
  • 注册成功,service worker 就在 ServiceWorkerGlobalScope 环境中运行,该环境与主线程独立,同时没有访问 DOM 的能力
  • 可以进行处理事件
  • service worker 控制的页面打开后会尝试去安装 service worker,最先发送给 service worker 的事件是安装事件(在该事件内可以开始进行填充 IndexDB 和缓存站点资源),让所有资源可以离线访问。
  • oninstall 事件处理程序执行完成之后,就可以认为 service worker 已经安装完成了
  • 然后是激活,service worker 安装完成之后,会收到激活事件。 onactivate 主要用途是清理先前版本的 service worker 脚本中使用的资源。
  • Service Worker 现在可以控制页面,但仅在 register() 成功后打开的页面,也就是说,页面起始于有没有 service worker 并且在接下来的生命周期维持这个状态,所以不得不重新加载让 service worker 重新获得控制。

支持的事件

installactivatemessagefetchsyncpush

注册 service worker

if('serviceWorker' in navigator){ // 确保浏览器支持 service worker
// 注册站点的 service worker
// 路径为相对于 origin 的文件路径,如 https://mdn.github.io/sw-test/sw.js 引入应该为 /sw-test/sw.js
// scope 为选填的内容
navigator.serviceWorker.register('/sw-test/sw.js',{scope:'/sw-test/'}).then(function(reg){
// worked
console.log('成功')
}).catch(function(error){
// failed
console.log('Registration failed with '+ error)
})
}

单个 service worker 可以控制很多页面,每个 scope 里的页面加载完的时候,安装在页面的 service worker 可以控制它,小心 service worker 中的全局变量,每个页面不会有自己独有的 worker。

安装和激活

this.addEventListener('install',function(event){
event.waitUntil(
caches.open('v1').then(function(cache){
return cache.addAll([
'/sw-test/',
'/sw-test/index.html',
'/sw-test/style.css',
'/sw-test/app.js',
'/sw-test/star-wars-logo.jpg',
])
})
)
})

localStorage 它是同步的,不允许在 service workers 内使用。

现在已经有了站点内容的缓存,你可以通过 fetch 事件告诉 service worker 让它用这些缓存内容。

所有被 service woker 控制的资源每次被请求到时,都会触发 fetch 事件吗